require 'rubygems'
require 'rake/clean'
require 'ffi'

require File.expand_path('../../lib/llvm/version', File.dirname(__FILE__))
include LLVM

def check_for(what, variants, env_var)
  variants = [ ENV[env_var], *variants ] if ENV.include?(env_var)

  $stdout.print("checking for #{what}... ")
  $stdout.flush

  result = variants.find do |variant|
    if yield(variant)
      $stdout.puts(variant)
      true
    end
  end

  if result
    result
  else
    raise RuntimeError, "Cannot find #{what}: tried #{variants}"
  end
end

def find_llvm_config
  check_for('llvm-config',
            %W(llvm-config-#{LLVM_VERSION} llvm-config),
            'LLVM_CONFIG') do |llvm_config|

    begin
      actual_version = `#{llvm_config} --version`.strip
      actual_maj, actual_min, _ = actual_version.split('.')

      required_maj, required_min = LLVM_VERSION.split('.')

      actual_maj == required_maj && actual_min == required_min
    rescue Errno::ENOENT
      false
    end
  end
end

def find_cxx
  check_for('C++ compiler', %W(g++ clang++), 'CXX') do |cxx|
    system(cxx, "--version", out: File::NULL, err: File::NULL)
    $?.success?
  end
end

LLVM_CONFIG = find_llvm_config
CXX         = find_cxx

def invoke_llvm_config(options)
  `#{LLVM_CONFIG} #{options}`.gsub("\n", " ")
end

SUPPORT_LIB = FFI.map_library_name("RubyLLVMSupport-#{LLVM_VERSION}")
CONFIG_MOD  = File.expand_path('../../lib/llvm/config.rb', File.dirname(__FILE__))

CLEAN.include(SUPPORT_LIB, CONFIG_MOD)

desc "Build the shared library and config module"
task :default => [SUPPORT_LIB, CONFIG_MOD]

file SUPPORT_LIB => %w(support.cpp) do |task|
  sh "#{CXX} -shared #{task.prerequisites.join(' ')} -lLLVM-#{LLVM_VERSION} " \
     "#{invoke_llvm_config('--cxxflags --ldflags')} -o #{SUPPORT_LIB}"
end

LLVM_CONFIG_OPTS = [
  ['COMPONENTS',    :array,  '--components'],
  ['TARGETS_BUILT', :array,  '--targets-built'],
  ['HOST_TARGET',   :string, '--host-target'],
  ['BUILD_MODE',    :string, '--build-mode'],
  ['CFLAGS',        :string, '--cflags'],
]

file CONFIG_MOD do
  open(CONFIG_MOD, 'w') do |f|
    f.puts '# Generated by ruby-llvm. Please do not change this file by hand.'
    f.puts 'module LLVM'
    f.puts '  module CONFIG'

    LLVM_CONFIG_OPTS.each do |(const, fmt, flag)|
      case fmt
      when :string
        value = invoke_llvm_config(flag)
      when :array
        value = invoke_llvm_config(flag).split
      end

      f.puts "    #{const} = #{value.inspect}"
    end

    f.puts '  end'
    f.puts 'end'
  end
end
